import {
  ElCascader,
  ElCheckbox,
  ElCheckboxGroup,
  ElColorPicker,
  ElDatePicker,
  ElInput,
  ElInputNumber,
  ElOption,
  ElRadio,
  ElRadioGroup,
  ElRate,
  ElSelect,
  ElSlider,
  ElSwitch,
  ElTreeSelect,
  ElUpload
} from 'element-plus';
import { ExtractPropTypes, Component } from 'vue';

/**
 * 定义表单的属性接口，用于配置表单的外观和行为
 */
export interface FFormProps {
  // 是否内联表单，默认为块级表单
  inline?: boolean;
  // 表单的架构定义，包括字段及其验证规则
  schema: FFSchema;
  // 表单数据模型，用于默认值数据绑定（不支持双向绑定）（和FFProperty的default同时存在时，优先default）
  model?: Record<string, any>;
  // 标签宽度，可以是数字表示像素值，或字符串表示其他单位
  labelWidth?: number | string;
  // 标签位置，可选值有左、右、顶
  labelPosition?: 'left' | 'right' | 'top';
  // 定义确定按钮的文本内容，可能为空
  sureText?: string;
  // 定义取消按钮的文本内容，可能为空
  cancelText?: string;
  // 定义确定按钮关联的图标，可能为空
  sureIcon?: string | Component;
  // 定义取消按钮关联的图标，可能为空
  cancelIcon?: string | Component;
  // 表单是否处于加载中状态
  loading?: boolean;
}

/**
 * 定义表单架构的接口，用于描述表单字段的验证规则和布局
 */
export interface FFSchema {
  // 字段属性定义
  properties: FFProperties;
  // 必填字段列表
  required?: string[];
  // 表单项之间的垂直间距，单位为像素
  gutter?: number;
  // 内联表单的宽度，可以是数字表示像素值，或字符串表示其他单位
  elementWidth?: number | string;
  // 字段布局配置
  layout?: FFLayout;
}

/**
 * 定义字段属性的接口，用于描述表单中每个字段的特性
 */
export interface FFProperties {
  // 字段名和字段属性的键值对
  [key: string]: FFProperty;
}

/**
 * 定义字段属性的接口，用于描述表单中每个字段的详细配置
 */
export interface FFProperty {
  // 字段的任意属性
  [key: string]: any;
  // 字段类型
  type: FFType;
  // 字段标题
  title: string;
  // 字段描述
  description?: string;
  // 字段默认值
  default?: any;
  // 字段枚举值列表
  enums?: FFEnum[];
  // 字段验证的正则表达式
  pattern?: string;
  // 字段格式，如电话、邮箱等
  format?: FFFormat;
  // 字段的UI配置
  ui?: FUI;
  // 是否条件渲染字段
  iif?: boolean;
  // 表单元素，可以是数字表示像素值，或字符串表示其他单位
  elementWidth?: number | string;
  // 字段布局配置
  layout?: FFLayout;
  // 表单项的规则
  rules?: FFRules[];
  // 提示
  tips?: string | Component;
}

/**
 * 定义字段规则的接口，用于描述表单中每个字段的验证规则
 */
export interface FFRules {
  [key: string]: any;
  message?: string;
  trigger?: 'blur' | 'change' | FFTrigger[];
  required?: boolean;
  pattern?: string;
  validator?: (rule: any, value: any, callback: any) => void;
}

/**
 * 定义字段触发方式的联合类型，表示字段验证的触发方式
 */
export type FFTrigger = 'blur' | 'change';

/**
 * 定义字段布局的接口，用于描述表单中每个字段的布局方式
 */
export interface FFLayout {
  // 栅栏宽度，占父容器宽度百分比
  span?: number;
  // 响应式布局，适用于不同屏幕大小
  xs?: number; // <576px
  sm?: number; // ≥576px
  md?: number; // ≥768px
  lg?: number; // ≥992px
  xl?: number; // ≥1200px
  // 栅栏偏移
  offset?: number;
}

/**
 * 定义字段类型的联合类型，表示字段可能的数据类型
 */
export type FFType =
  | 'string'
  | 'number'
  | 'boolean'
  | 'array'
  | 'object'
  | 'null'
  | 'undefined'
  | 'symbol'
  | 'bigint'
  | 'function';

/**
 * 定义字段枚举值的接口，用于描述表单中每个字段的枚举选项
 */
export interface FFEnum {
  // 枚举值
  value: any;
  // 枚举标签
  label: string;
  // 是否禁用枚举选项
  disabled?: boolean;
  // 子枚举选项，用于级联选择
  children?: FFEnum[];
}

/**
 * 定义字段格式的联合类型，表示字段可能的格式类型
 */
export type FFFormat = 'phone' | 'email';

/**
 * 定义字段UI配置的接口，用于描述表单中每个字段的UI特性
 */
export interface FUI {
  // 字段使用的组件类型
  widget?: FFWidget;
  // 组件属性配置
  props?: FFInput &
    FFSelect &
    FFCascader &
    FFColorPicker &
    FFDatePicker &
    FFInputNumber &
    FFRadioGroup &
    FFRate &
    FFSlider &
    FFSwitch &
    FFTreeSelect &
    FFUpload &
    FFCheckbox;
  childrenProps?: FFRadio & FFCheckboxGroup & FFSelectOption;
  // 异步数据加载函数
  asyncData?: () =>
    | Promise<any[]>
    | any[]
    | Promise<unknown[]>
    | Promise<FFEnum[]>;
}

/**
 * 定义了一个类型别名 FFWidget，它代表了一组特定的字符串字面量。
 * 这些字符串代表了不同的表单控件或选择器类型，例如复选框、级联选择器、颜色选择器等。
 * 使用类型别名可以方便地定义和管理这些表单控件的类型，确保类型安全和代码的一致性。
 */
export type FFWidget =
  | 'checkbox' // 复选框
  | 'cascader' // 级联选择器
  | 'color' // 颜色选择器
  | 'year' // 年份选择器
  | 'years' // 年份范围选择器
  | 'month' // 月份选择器
  | 'months' // 月份范围选择器
  | 'date' // 日期选择器
  | 'dates' // 日期范围选择器
  | 'datetime' // 日期时间选择器
  | 'week' // 星期选择器
  | 'datetimerange' // 日期时间范围选择器
  | 'daterange' // 日期范围选择器
  | 'monthrange' // 月份范围选择器
  | 'yearrange' // 年份范围选择器
  | 'number' // 数字输入框
  | 'radio' // 单选框
  | 'rate' // 评分控件
  | 'select' // 下拉选择框
  | 'slider' // 滑动条
  | 'switch' // 开关
  | 'tree-select' // 树形选择器
  | 'upload'; // 文件上传控件

/**
 * 定义FFInput接口，继承自ElInput组件的props类型
 * 通过ExtractPropTypes获取ElInput组件props的类型，确保类型安全和一致性
 */
export interface FFInput extends ExtractPropTypes<(typeof ElInput)['props']> {}

/**
 * 定义FFSelect接口，继承自ElSelect组件的props类型
 * 通过ExtractPropTypes获取ElSelect组件props的类型，确保类型安全和一致性
 */
export interface FFSelect
  extends ExtractPropTypes<(typeof ElSelect)['props']> {}

/**
 * 定义FFRadio接口，继承自ElRadio组件的props类型
 * 通过ExtractPropTypes获取ElRadio组件props的类型，确保类型安全和一致性
 */
export interface FFRadio extends ExtractPropTypes<(typeof ElRadio)['props']> {}

/**
 * 定义FFCheckbox接口，继承自ElCheckbox组件的props类型
 * 通过ExtractPropTypes获取ElCheckbox组件props的类型，确保类型安全和一致性
 */
export interface FFCheckbox
  extends ExtractPropTypes<(typeof ElCheckbox)['props']> {}

/**
 * 定义FFCascader接口，继承自ElCascader组件的props类型
 * 通过ExtractPropTypes获取ElCascader组件props的类型，确保类型安全和一致性
 */
export interface FFCascader
  extends ExtractPropTypes<(typeof ElCascader)['props']> {}

/**
 * 定义FFColorPicker接口，继承自ElColorPicker组件的props类型
 * 通过ExtractPropTypes获取ElColorPicker组件props的类型，确保类型安全和一致性
 */
export interface FFColorPicker
  extends ExtractPropTypes<(typeof ElColorPicker)['props']> {}

/**
 * 定义FFDatePicker接口，继承自ElDatePicker组件的props类型
 * 通过ExtractPropTypes获取ElDatePicker组件props的类型，确保类型安全和一致性
 */
export interface FFDatePicker
  extends ExtractPropTypes<(typeof ElDatePicker)['props']> {}

/**
 * 定义FFInputNumber接口，继承自ElInputNumber组件的props类型
 * 通过ExtractPropTypes获取ElInputNumber组件props的类型，确保类型安全和一致性
 */
export interface FFInputNumber
  extends ExtractPropTypes<(typeof ElInputNumber)['props']> {}

/**
 * 定义FFRadioGroup接口，继承自ElRadioGroup组件的props类型
 * 通过ExtractPropTypes获取ElRadioGroup组件props的类型，确保类型安全和一致性
 */
export interface FFRadioGroup
  extends ExtractPropTypes<(typeof ElRadioGroup)['props']> {}

/**
 * 定义FFRate接口，继承自ElRate组件的props类型
 * 通过ExtractPropTypes获取ElRate组件props的类型，确保类型安全和一致性
 */
export interface FFRate extends ExtractPropTypes<(typeof ElRate)['props']> {}

/**
 * 定义FFSelectOption接口，继承自ElOption组件的props类型
 * 通过ExtractPropTypes获取ElOption组件props的类型，确保类型安全和一致性
 */
export interface FFSelectOption
  extends ExtractPropTypes<(typeof ElOption)['props']> {}

/**
 * 定义FFSlider接口，继承自ElSlider组件的props类型
 * 通过ExtractPropTypes获取ElSlider组件props的类型，确保类型安全和一致性
 */
export interface FFSlider
  extends ExtractPropTypes<(typeof ElSlider)['props']> {}

/**
 * 定义FFSwitch接口，继承自ElSwitch组件的props类型
 * 通过ExtractPropTypes获取ElSwitch组件props的类型，确保类型安全和一致性
 */
export interface FFSwitch
  extends ExtractPropTypes<(typeof ElSwitch)['props']> {}

/**
 * 定义FFTreeSelect接口，继承自ElTreeSelect组件的props类型
 * 通过ExtractPropTypes获取ElTreeSelect组件props的类型，确保类型安全和一致性
 */
export interface FFTreeSelect
  extends ExtractPropTypes<(typeof ElTreeSelect)['props']> {}

/**
 * 定义FFUpload接口，继承自ElUpload组件的props类型
 * 通过ExtractPropTypes获取ElUpload组件props的类型，确保类型安全和一致性
 */
export interface FFUpload
  extends ExtractPropTypes<(typeof ElUpload)['props']> {}

/**
 * 定义FFCheckboxGroup接口，继承自ElCheckboxGroup组件的props类型
 * 通过ExtractPropTypes获取ElCheckboxGroup组件props的类型，确保类型安全和一致性
 */
export interface FFCheckboxGroup
  extends ExtractPropTypes<(typeof ElCheckboxGroup)['props']> {}
